/*
 * @Descripttion:
 * @version:
 * @Author: congsir
 * @Date: 2022-06-06 15:42:32
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2022-09-02 17:42:15
 */
import { Color, Component, Material, MeshRenderer, Node, primitives, utils, Vec2, Vec3, Vec4, _decorator } from 'cc';
import { DataUtils } from './DataUtils';

const { ccclass, property } = _decorator;

interface IterrainInfo {
    width: number;
    height: number;
    segmentX: number;
    segmentY: number;
    min: number;
    max: number;
}

interface IIMeshInfo {
    vertices: Vec3[];
    uvs: Vec2[];
    triangles: number[];
    vColor: Vec4[];
}

@ccclass('HeatMapCOMP')
export class HeatMapCOMP extends Component {
    @property(Color)
    public color1: Color = null;

    @property(Color)
    public color2: Color = null;

    @property(Color)
    public color3: Color = null;

    @property(Color)
    public color4: Color = null;

    @property(Material)
    public diffuseMap: Material = null; // 材质

    private vertices2: Array<Vec3[]> = [];

    // 生成信息
    private size: Vec2; // 长宽

    private segment: Vec2;

    // 面片mesh
    private terrain: Node;

    public onLoad() {
        // 生成地形
        this.setTerrain({ width: 200, height: 200, segmentX: 50, segmentY: 50, min: -10, max: 10 });
    }

    public getHeatMapData(segmentX: number, segmentY: number): Array<number[]> {
        let heatMapdata = [
            [1, 2, 3, 4, 5, 16, 7, 8, 9, 20],
            [2, 0, 3, 5, 16, 1, 40, 9, 10, 8],
            [0, 0, 3, 4, 6, 7, 30, 9, 10, 8],
            [4, 2, 3, 5, 5, 1, 30, 4, 0, 18],
            [0, 2, 3, 5, 16, 7, 30, 1, 0, 8],
            [6, 2, 3, 5, 6, 17, 1, 39, 10, 0],
        ];

        return DataUtils.scaleData({ w: segmentX + 1, h: segmentY + 1, data: heatMapdata }, 2);
        // return this.lerp2DArr(segmentX + 1, segmentY + 1, heatMapdata);
        // return heatMapdata;
    }

    // 对二维数组进行线性插值
    public lerp2DArr(targetRow: number, targetColumn: number, data: Array<number[]>) {
        console.log('targetRow', targetRow);

        let srcRow = data.length;
        let srcColumn = data[0].length;

        // x方向插值 两个点插值多少个数
        let lerpXCount = Math.floor(targetColumn / srcColumn);
        let lerpYCount = Math.floor(targetRow / srcRow);

        console.log('lerpXCount', lerpXCount);
        console.log('lerpYCount', lerpYCount);

        //   插值数组初始化 targetRow*srcColumn
        let LerpArr: Array<number[]> = [];
        for (let i = 0; i < targetRow; i++) {
            let tempArr = [];
            for (let j = 0; j < targetColumn; j++) {
                tempArr.push(0);
            }
            LerpArr.push(tempArr);
        }

        // X方向插值

        for (let m = 0; m < srcRow; m++) {
            for (let n = 0; n < srcColumn - 1; n++) {
                let curVal = data[m][n];
                let nextVal = data[m][n + 1];
                let tempGapX = (nextVal - curVal) / lerpXCount;

                for (let x = 0; x < lerpXCount; x++) {
                    LerpArr[m * lerpYCount][n * lerpXCount + x] = tempGapX * x + curVal;
                }
            }
        }

        // y方向插值
        for (let i = 0; i < targetRow - 1; i += lerpYCount) {
            for (let j = 0; j < targetColumn; j++) {
                // 第i行 和 第i+lerpYCount行的对应元素插值，填充第i行和第i+lerpYCount的之间的行
                if (i + lerpXCount > targetRow) {
                    return LerpArr;
                }
                let tempGapY = (LerpArr[i + lerpYCount][j] - LerpArr[i][j]) / lerpYCount;

                for (let x = 0; x < lerpYCount; x++) {
                    LerpArr[x + i][j] = tempGapY * x + LerpArr[i][j];
                }
            }
        }
    }

    // 更改plane的顶点高度
    public refreshMesh(vertices: Vec3[]) {
        let data = this.getHeatMapData(this.segment.x, this.segment.y);
        console.log('data', data);

        let vColor: Vec4[] = [];

        for (let i = 0; i < data.length; i++) {
            let item = data[i];
            for (let j = 0; j < item.length; j++) {
                let height = item[j];
                this.vertices2[i][j].y = height;
                vertices[i * data[0].length + j].y = height;
                vColor[i * data[0].length + j] = this.getColor(height);
            }
        }
        return { vertices, vColor };
    }

    /**
     * @name: setTerrain
     * @msg: 生成地形
     * @param {number} width  地形宽度
     * @param {number} height 地形长度
     * @param {number} segmentX 宽度的段数
     * @param {number} segmentY 长度的段数
     * @param {number} min 最低高度
     * @param {number} max  最高高度
     * @return {*}
     * */

    public setTerrain(info: IterrainInfo) {
        this.init(info);

        let vertices = this.getVertices();
        let uvs = this.getUV();
        let triangles = this.getTriangles();

        let verticesInfo = this.refreshMesh(vertices);

        this.drawMesh({ vertices: verticesInfo.vertices, uvs: uvs, triangles: triangles, vColor: verticesInfo.vColor });
    }

    /**
     * @name: getColor
     * @msg: 根据顶点高度返回顶点颜色值
     * @param {number} height
     * @return {*}
     */
    private getColor(height: number): Vec4 {
        let vColor: Vec4 = new Vec4(0, 0, 0, 0);

        // 计算顶点颜色
        if (height >= 30) {
            vColor = new Vec4(this.color1.r, this.color1.g, this.color1.b, this.color1.a).divide4f(255, 255, 255, 255);
        } else if (height >= 20) {
            vColor = new Vec4(this.color2.r, this.color2.g, this.color2.b, this.color2.a).divide4f(255, 255, 255, 255);
        } else if (height >= 10) {
            vColor = new Vec4(this.color3.r, this.color3.g, this.color3.b, this.color3.a).divide4f(255, 255, 255, 255);
        } else {
            vColor = new Vec4(this.color4.r, this.color4.g, this.color4.b, this.color4.a).divide4f(255, 255, 255, 255);
        }
        if (vColor.equals4f(0, 0, 0, 0)) {
            console.log('根据顶点高度返回顶点颜色值', height);
        }

        return vColor;
    }

    // 初始化计算某些值
    private init(info: IterrainInfo) {
        this.size = new Vec2(info.width, info.height);
        this.segment = new Vec2(info.segmentX, info.segmentY);
        console.log(' this.segment', this.segment);

        if (this.terrain) {
            this.terrain.destroy();
        }
        this.terrain = new Node();
        this.terrain.parent = this.node;
        this.terrain.name = 'plane';
    }

    // 生成顶点信息
    private getVertices(): Array<Vec3> {
        const sum = Math.floor((this.segment.x + 1) * (this.segment.y + 1)); // 顶点的总数量 一个地图是4*2 一共8个格子，但是有15个顶点

        let w = this.size.x / this.segment.x;
        let h = this.size.y / this.segment.y;

        let index = 0;
        let vertices = new Array<Vec3>(sum);

        for (let i = 0; i < this.segment.y + 1; i++) {
            let tempArr: Vec3[] = [];
            for (let j = 0; j < this.segment.x + 1; j++) {
                // 顶点是一行一行创建的
                tempArr.push(new Vec3(j * w, 0, i * h));
                vertices[index] = new Vec3(j * w, 0, i * h);
                index++;
            }
            this.vertices2.push(tempArr);
        }

        return vertices;
    }

    // 生成UV信息
    private getUV(): Array<Vec2> {
        const sum = Math.floor((this.segment.x + 1) * (this.segment.y + 1));
        let uvs: Vec2[] = [];
        let u = 1 / this.segment.x;
        let v = 1 / this.segment.y;
        for (let i = 0; i < this.segment.y + 1; i++) {
            for (let j = 0; j < this.segment.x + 1; j++) {
                uvs.push(new Vec2(j * u, i * v));
            }
        }
        return uvs;
    }

    // 生成顶点索引数组
    private getTriangles(): number[] {
        // 绘制一个格子需要6个顶点， 绘制 this.segment.x * this.segment.y个格子
        const num = this.segment.x * this.segment.y * 6;
        let triangles: number[] = new Array<number>(num);
        for (let ti = 0, vi = 0, y = 0; y < this.segment.y; y++, vi++) {
            for (let x = 0; x < this.segment.x; x++, ti += 6, vi++) {
                triangles[ti] = vi;
                triangles[ti + 3] = triangles[ti + 2] = vi + 1;
                triangles[ti + 4] = triangles[ti + 1] = vi + this.segment.x + 1;
                triangles[ti + 5] = vi + this.segment.x + 2;
            }
        }
        return triangles;
    }

    private drawMesh(meshInfo: IIMeshInfo) {
        let meshRenderer = this.terrain.addComponent(MeshRenderer);
        // 材质不存在
        if (this.diffuseMap === null) {
            // console.error('材质不存在');
            return;
        }
        meshRenderer.material = this.diffuseMap;

        let positons: number[] = [];
        meshInfo.vertices.forEach((value) => {
            positons.push(value.x, value.y, value.z);
        });

        let tempUvs: number[] = [];
        meshInfo.uvs.forEach((value) => {
            tempUvs.push(value.x, value.y);
        });

        let colors: number[] = [];
        meshInfo.vColor.forEach((val) => {
            colors.push(val.x, val.y, val.z, val.w);
        });

        let meshInfoRes: primitives.IGeometry = {
            positions: positons,
            indices: meshInfo.triangles,
            uvs: tempUvs,
            colors: colors,
        };

        let mesh = utils.createMesh(meshInfoRes);
        meshRenderer.mesh = mesh;
    }
}
